import java.io.BufferedReader;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

public class Main {

    /**
     * @param args
     */
    public static void main(String[] args) {
	Main main = new Main();
	List<Produccion> producciones = main.leerGramatica();
	main.llenarPrimeroSiguiente(producciones);
	List<String> simbolos = main.leerSimbolos(producciones);
	String[][] tabla = main.armarTabla(producciones, simbolos);
	
	main.imprimirTabla(producciones, simbolos, tabla);
    }

    private void imprimirTabla(List<Produccion> producciones, List<String> simbolos, String[][] tabla) {
	final int espacios = 15;
	List<String> cabeceras = new ArrayList<String>();
	cabeceras.add("No terminal");
	cabeceras.addAll(simbolos);
	for(String c : cabeceras){
	    int espacio = espacios - c.length();
	    String espacioS = "";
	    for(int i = 0; i < espacio; i++){
		espacioS += " ";
	    }
	    System.out.print(c + espacioS);
	}
	System.out.println();
	for(int i = 0; i < producciones.size(); i++){
	    List<String> fila = new ArrayList<String>();
	    fila.add(producciones.get(i).getNoTerminal());
	    fila.addAll(Arrays.asList(tabla[i]));
	    for(String f : fila){
		String dato = null == f ? "" : f;
		int espacio = espacios - dato.length();
		String espacioS = "";
		for(int j = 0; j < espacio; j++){
		    espacioS += " ";
		}
		System.out.print(dato + espacioS);
	    }
	    System.out.println();
	}
    }

    private String[][] armarTabla(List<Produccion> producciones, List<String> simbolos) {
	String[][] tabla = new String[producciones.size()][simbolos.size()];
	for(Produccion p : producciones){
	    List<Produccion.Entrada> entradas = p.generarEntradas();
	    for(Produccion.Entrada e : entradas){
		tabla[producciones.indexOf(p)][simbolos.indexOf(e.getSimbolo())] = e.getProduccion();
	    }
	}
	
	return tabla;
    }

    private List<String> leerSimbolos(List<Produccion> producciones) {
	List<String> simbolos = new ArrayList<String>();
	for(Produccion p : producciones){
	    for(String s : p.getPrimeros()){
		if(!simbolos.contains(s)){
		    simbolos.add(s);
		}
	    }
	    for(String s : p.getSiguientes()){
		if(!simbolos.contains(s)){
		    simbolos.add(s);
		}
	    }
	}
	return simbolos;
    }

    private void llenarPrimeroSiguiente(List<Produccion> producciones) {
	final File entrada = new File("src/archivos/primeros_siguientes.txt");
	BufferedReader reader = null;
	FileReader fReader = null;
	try {
	    fReader = new FileReader(entrada);
	    reader = new BufferedReader(fReader);
	    String line = reader.readLine();
	    while(true){
		if(null == line || line.isEmpty() || line.trim().startsWith("#")){
		    break;
		}
		String restoDeLinea = line.substring(line.indexOf("(") + 2, line.length()).trim();
		String noTerminal = line.substring(line.indexOf("(") + 2, line.indexOf("(") + 2 + restoDeLinea.indexOf(")")).trim();

		Produccion pr = null;
		for(Produccion p : producciones){
		    if(noTerminal.equals(p.getNoTerminal())){
			pr = p;
			break;
		    }
		}

		restoDeLinea = line.substring(line.indexOf("{") + 1, line.lastIndexOf("}")).trim();
		String[] simbolos = restoDeLinea.split(",");

		if(line.trim().startsWith("primero")){
		    for(String simbolo : simbolos){
			if(!pr.getPrimeros().contains(simbolo.trim()) && !"null".equals(simbolo.trim())){
			    pr.getPrimeros().add(simbolo.trim());
			}
		    }
		}else if(line.trim().startsWith("siguiente")){
		    for(String simbolo : simbolos){
			if(!pr.getSiguientes().contains(simbolo.trim()) && !"null".equals(simbolo.trim())){
			    pr.getSiguientes().add(simbolo.trim());
			}
		    }
		}
		line = reader.readLine();
	    }
	} catch (FileNotFoundException e) {
	    e.printStackTrace();
	    System.exit(-1);
	} catch (IOException e) {
	    e.printStackTrace();
	    System.exit(-1);
	}finally{
	    try{
		fReader.close();
		reader.close();
	    }catch (IOException e) {
		e.printStackTrace();
		System.exit(-1);
	    }
	}
    }

    private List<Produccion> leerGramatica() {
	final File entrada = new File("src/archivos/gramatica.txt");
	BufferedReader reader = null;
	FileReader fReader = null;
	List<Produccion> producciones = new ArrayList<Produccion>();
	try {
	    fReader = new FileReader(entrada);
	    reader = new BufferedReader(fReader);
	    String line = reader.readLine();
	    while(true){
		if(null == line || line.isEmpty()){
		    break;
		}
		String noTerminal = line.substring(0,line.indexOf("-->")).trim();
		String prod1 = null;
		String prod2 = null;
		if(line.contains("|")){
		    prod1 = line.substring(0, line.indexOf("|")).trim();
		    if("null".equals(line.substring(line.indexOf("|") + 1, line.length()).trim())){
			prod2 = (line.substring(0, line.indexOf(">") + 1) + " " + new Character('\u025b')).trim();
		    }else{
			prod2 = (line.substring(0, line.indexOf(">") + 1) +
				line.substring(line.indexOf("|") + 1, line.length())).trim();
		    }
		}else{
		    prod1 = line.substring(0).trim();
		}
		producciones.add(new Produccion(noTerminal, prod1, prod2));
		line = reader.readLine();
	    }
	} catch (FileNotFoundException e) {
	    e.printStackTrace();
	    System.exit(-1);
	} catch (IOException e) {
	    e.printStackTrace();
	    System.exit(-1);
	}finally{
	    try{
		fReader.close();
		reader.close();
	    }catch (IOException e) {
		e.printStackTrace();
		System.exit(-1);
	    }
	}

	return producciones;

    }

}
